#include <sys_config.h>
#include <retcode.h>
#include <types.h>
#include <osal/osal.h>
#include <api/libc/alloc.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <hal/hal_gpio.h>
//#include <bus/spi/spi.h>
#include <hld/hld_dev.h>
#include <hld/nim/nim_dev.h>
#include <hld/nim/nim_tuner.h>
#include <hld/nim/nim.h>
#include <bus/i2c/i2c.h>
#include <math.h>
#include <api/libosd/osd_lib.h>

#include "nim_dib8000.h"

#include <adapter/frontend.h>
#include <adapter/frontend_tune.h>
#include <adapter/sip.h>
#include <sip/dib8090.h>
#include <demod/dib8000.h>
#include <adapter/databus.h>
#include <adapter/demod.h>
#include <adapter/frontend.h>

#include "dibcom/monitor/monitor.h"

#ifdef CONFIG_DEBUG
	#define NIM_PRINTF libc_printf
	#define ALI_PRINTF libc_printf
#else
	#define NIM_PRINTF(...)
	#define ALI_PRINTF(...)
#endif

//#define ALI_PRINTF libc_printf


#if 1
	#define US_TICKS        (sys_ic_get_cpu_clock()*1000000 / 2000000) //(SYS_CPU_CLOCK / 2000000)
	#define WAIT_1ms        (1000* US_TICKS)
	#define WAIT_100ms	1
OSAL_ID f_IIC_Sema_ID = OSAL_INVALID_ID;
ID f_dib8000_CC_tracking_task_id = OSAL_INVALID_ID;

#endif
ID f_dib8000_monitor_task_id = OSAL_INVALID_ID;
DWORD g_last_channel_change_time = 0xFFFFFFF;

#define NIM_MAX_UNLOCK_COUNT              8 
#if 1 /*Fix manualscan will fail to lock again for dib8000 demod*/
	#define NIM_SYR_UNLOCK_MAX_COUNT          1
	#define NIM_TPS_PRF_LK_UNLOCK_MAX_COUNT   1 
#else
	#define NIM_SYR_UNLOCK_MAX_COUNT          8 
	#define NIM_TPS_PRF_LK_UNLOCK_MAX_COUNT   8 
#endif

static OSAL_ID l_nim_8000_sema_id;
static struct dib8000_Lock_Info   *dib8000_CurChannelInfo;
struct nim_dib8000_private  *gNim_dib8000_private;
UINT8 dib8000_autoscan_stop_flag = 0;

static char nim_dib8000_name[HLD_MAX_NAME_SIZE] = "NIM_DIB8000_0";

static struct dibFrontend frontend[2];
static struct dibDataBusHost *i2c;
struct dibDemodMonitor mon[2];

//refer to sample_nim8096gp_lt.c
static const struct dib8090_config nim8096md_config[2] = {
    {
        1,
        NULL, // update_lna

        DIB8090_GPIO_DEFAULT_DIRECTIONS,
        DIB8090_GPIO_DEFAULT_VALUES,
        DIB8090_GPIO_DEFAULT_PWM_POS,

        -143,     // dib0070_freq_offset_khz_uhf
        -143,     // dib0070_freq_offset_khz_vhf

        0,
        12000, // clock_khz
        4,
        0,
        0,
        1, // use_high_level_adjustment
        0,

        0x2d00, // dib8k_drives
        144,    //diversity_delay
        0x31,  //div_cfg
        1, // clkouttobamse
        1, // clkoutdrive
        3, // refclksel
        6, // fref_clock_ratio
    },
    {
        1,
        NULL, // update_lna

        DIB8090_GPIO_DEFAULT_DIRECTIONS,
        DIB8090_GPIO_DEFAULT_VALUES,
        DIB8090_GPIO_DEFAULT_PWM_POS,

        -63,     // dib0070_freq_offset_khz_uhf
        -143,     // dib0070_freq_offset_khz_vhf

        0,
        12000, // clock_khz
        4,
        0,
        0,
        1,//0,
        0,

        0x2d08, // dib8k_drives
        1,   //diversity_delay
        0x31,  //div_cfg
        1, //clkouttobamse
        1, // clkoutdrive
        3, // refclksel
        6, // fref_clock_ratio
    },
};

#define BEST_BER 50000
#define ZERO_BER 2097151//10000000
//#define DIB_I2C_ID 0

BOOL g_bdevicefail = FALSE;
DiBcom_GetStrength(UINT16 *pu16Strength)
{
	UINT16 v = data_bus_client_read16(demod_get_data_bus_client(&frontend),568);
	UINT8 mpeg_data_lock = ((v >> 5) & 7);
	v = data_bus_client_read16(demod_get_data_bus_client(&frontend), 390);

	//libc_printf("\n",v);
	UINT16 signal_strength = (100 - ((v * 100) / 65535));

	//libc_printf("DiBcom_GetStrength\n");
	*pu16Strength = signal_strength;
	NIM_PRINTF("DiBcom_GetStrength = %d\n", *pu16Strength);

	return 1;
}

DiBcom_GetQuality(UINT16 *pu16Quality)
{
	double tmp = log10(ZERO_BER)-log10(BEST_BER);
	double CUR_BER;

	UINT32 bit_error_rate;
	UINT16 v = data_bus_client_read16(demod_get_data_bus_client(&frontend),568);
	UINT8 mpeg_data_lock = ((v >> 5) & 7);

	  if (mpeg_data_lock)
        	bit_error_rate = data_bus_client_read32(demod_get_data_bus_client(&frontend),560);
    	else
        	bit_error_rate = 2097151;

	//libc_printf("DiBcom_GetQuality\n");

	if (bit_error_rate == 0)
		*pu16Quality = 100;
	else if (bit_error_rate <= BEST_BER)
		*pu16Quality = 99;
	else if (bit_error_rate >= ZERO_BER)
		*pu16Quality = 0;
	else
	{
		CUR_BER = log10(bit_error_rate);
		*pu16Quality = (int)((log10(ZERO_BER) - CUR_BER)/tmp*100); //100;
	}

	return 1;
}



INT8 f_dibcom_read(UINT8 dev_addr, UINT8 *tx, UINT16 tx_len, UINT8 *rx, UINT16 rx_len)
{
	INT8 err;
	UINT8 buf[tx_len+rx_len];
	int i;
    UINT32 i2c_id = gNim_dib8000_private->Tuner_Control.ext_dm_config.i2c_type_id;    

	osal_semaphore_capture(f_IIC_Sema_ID,TMO_FEVR);

	if ((dev_addr&0xF0) == 0xC0)
	{
		for (i=0; i< tx_len;i++)
		{
			rx[i] = tx[i];
		}
		//i2c_gpio_write_read(DIB_I2C_ID, dev_addr, rx, tx_len, rx_len);
        i2c_write_read(i2c_id, dev_addr, rx, tx_len, rx_len);
	}
	else
	{
		//err = i2c_gpio_write(DIB_I2C_ID, dev_addr, tx, tx_len);
        err = i2c_write(i2c_id, dev_addr, tx, tx_len);
		if (err != SUCCESS)
		{
			ALI_PRINTF("read_R_w==> %d, i2c_id: 0x%x, dev_addr: 0x%x\n",err, i2c_id, dev_addr);
            ;
		}
		//err = i2c_gpio_read(DIB_I2C_ID ,dev_addr, rx, rx_len);
		err = i2c_read(i2c_id, dev_addr, rx, rx_len);
		if (err != SUCCESS)
		{
            ALI_PRINTF("read_R_r==> %d, i2c_id: 0x%x, dev_addr: 0x%x\n",err, i2c_id, dev_addr);
			;
		}
	}

	//osal_task_sleep(10);
	osal_semaphore_release(f_IIC_Sema_ID);
	return SUCCESS;
}

INT8 f_dibcom_write(UINT8 dev_addr, UINT8 *tx, UINT16 tx_len)
{
	INT32 err;
    UINT32 i2c_id = gNim_dib8000_private->Tuner_Control.ext_dm_config.i2c_type_id;

    osal_semaphore_capture(f_IIC_Sema_ID,TMO_FEVR);

//	dev_addr = dev_addr;

	//err=i2c_gpio_write(DIB_I2C_ID, dev_addr, tx, tx_len);
	err = i2c_write(i2c_id, dev_addr, tx, tx_len);
	if (err != SUCCESS)
	{
        ALI_PRINTF("W==> %d, i2c_id: 0x%x, dev_addr: 0x%x\n",err, i2c_id, dev_addr);
		;
	}

	osal_semaphore_release(f_IIC_Sema_ID);
	return SUCCESS;
}

//detect a connected status of a wire
static INT32 f_nim8000_CC_Tracking()
{
	struct dibChannel ch;

    
	ALI_PRINTF("f_nim8000_CC_Tracking...\n");

	osal_semaphore_capture(l_nim_8000_sema_id, TMO_FEVR);
        
	INIT_CHANNEL(&ch, STANDARD_ISDBT);
	ch.RF_kHz           = dib8000_CurChannelInfo->CC_Tracking_Frequency;
	ch.bandwidth_kHz    = dib8000_CurChannelInfo->CC_Tracking_ChannelBW * 1000;

	tune_diversity(&frontend, 1, &ch);

    if(frontend_get_status(&frontend) == FE_STATUS_LOCKED)
    {
		ALI_PRINTF("f_nim8000_CC_Tracking SUCCESS !!!\n");
    	dib8000_CurChannelInfo->Lock_Val = 1;
    }
    else
    {
        dib8000_CurChannelInfo->Lock_Val = 0;
		ALI_PRINTF("f_nim8000_CC_Tracking FAIL !!!\n");
    }

	osal_semaphore_release(l_nim_8000_sema_id);
        
    return SUCCESS;
}

void dib8000_Tracking()
{
	UINT16 v = data_bus_client_read16(demod_get_data_bus_client(frontend),568);
	UINT8 mpeg_data_lock;// = (v >>  6) & 1;
	static UINT8 lock_count = 0;
	static UINT8 TK_Count = 0;
	UINT8 tmccg_sync_lock=0;

	if(( (v >>  5) & 1)||( (v >>  6) & 1)||( (v >>  7) & 1))	
		mpeg_data_lock=1;
	else
		mpeg_data_lock=0;
	
	if( (v >> 3) & 1)
		tmccg_sync_lock=1;
	else
		tmccg_sync_lock=0;
	

	if ((tmccg_sync_lock)&&(mpeg_data_lock))	
	{
		lock_count = 0;
		if (dib8000_CurChannelInfo->Lock_Val == 0)
		{
			dib8000_CurChannelInfo->Lock_Val = 1;
		}
	}
	else
	{
		if (dib8000_CurChannelInfo->Lock_Val == 1)
		{
			if (++lock_count == NIM_MAX_UNLOCK_COUNT)
			{
				dib8000_CurChannelInfo->Lock_Val = 0;
				lock_count = 0;
			}
		}
	}

	if (dib8000_CurChannelInfo->Lock_Val == 1)
		TK_Count = 0;
	else 
    {
		if (++TK_Count == NIM_MAX_UNLOCK_COUNT)
        {
			if (!dib8000_CurChannelInfo->CC_Tracking_flag)
			{
				f_nim8000_CC_Tracking(); //detect a connected status of a wire
			}
 			TK_Count = 0;
        }
    }
}

#if 0
extern CONTAINER win_factoryset_con;
extern CONTAINER g_win_misc_setting;
extern CONTAINER g_win_antenna_set_fixed;
#endif
static INT32 f_dib8000_get_lock_status(struct nim_device *dev, UINT8 *lock)
{
	UINT16 v = data_bus_client_read16(demod_get_data_bus_client(frontend),/*509*/568);
	//libc_printf("get lock = 0x%x\n",v);
	
	UINT8 mpeg_data_lock=0;
	UINT8 tmccg_sync_lock=0;
	
	/*modified by alex 2010.11.18*/
	mpeg_data_lock = !!((v >> 5) & 7);	// if lock !!((v >> 5) & 7) = 1;

	if( (v >>  3) & 1)	
		tmccg_sync_lock=1;
	else
		tmccg_sync_lock=0;

	if ((tmccg_sync_lock)) //&&(mpeg_data_lock)
	{	
		*lock = 1;
		dib8000_CurChannelInfo->Lock_Val = 1;
	}
	else
	{	
		*lock = 0;
		dib8000_CurChannelInfo->Lock_Val = 0;
		/*if (menu_stack_get_top() == (POBJECT_HEAD)&g_win_misc_setting || menu_stack_get_top() == (POBJECT_HEAD)&g_win_antenna_set_fixed || menu_stack_get_top() == NULL)
		{
			dib8000_Tracking();
		}*/
	}
	return SUCCESS;
}


#if 1 /*Fix manualscan will fail to lock again for dib8000 demod*/
static BOOL CheckChannelChange(UINT32 freq, UINT8 bandwidth)
{
	if (freq == dib8000_CurChannelInfo->CC_Tracking_Frequency && bandwidth == dib8000_CurChannelInfo->CC_Tracking_ChannelBW)
		return FALSE;
	return TRUE;
}
#endif

static INT32 f_dib8000_channel_change(struct nim_device *dev, UINT32 freq, UINT32 bandwidth, 
									   UINT8 guard_interval, UINT8 fft_mode, UINT8 modulation, UINT8 fec, UINT8 usage_type, UINT8 inverse, UINT8 priority)
{
	INT32 ret_code;
	UINT32  fft_Mode;
	UINT32  Guard;
	static struct dibChannel ch;
	struct nim_dib8000_private *dev_priv;  
	dev_priv = gNim_dib8000_private;
	UINT8 lock=0;
    UINT8 count;

	ALI_PRINTF("dib8000_CG_start! freq=%d bandwidth:%d\n",freq, bandwidth);
 //   libc_printf("start %d\n", osal_get_tick());
	osal_semaphore_capture(l_nim_8000_sema_id, TMO_FEVR);

	dib8000_CurChannelInfo->CC_Tracking_staus=0;

#if 1 /*Fix manualscan will fail to lock again for dib8000 demod*/
	if (dib8000_CurChannelInfo->Lock_Val == 1 && !CheckChannelChange(freq, bandwidth))
	{
        g_last_channel_change_time = osal_get_tick();
		osal_semaphore_release(l_nim_8000_sema_id);
		return SUCCESS;
	}
#endif

	dib8000_CurChannelInfo->CC_Tracking_flag = 1; //TRACKING CHECK IF HAVE DONE CC, TRACKING RESET.
	dib8000_CurChannelInfo->Lock_Val = 0;

	INIT_CHANNEL(&ch, STANDARD_ISDBT);
	ch.RF_kHz           = dib8000_CurChannelInfo->Frequency = freq;
	ch.bandwidth_kHz    = bandwidth * 1000;
	dib8000_CurChannelInfo->ChannelBW = bandwidth;

	if (dib8000_autoscan_stop_flag)
	{
        g_last_channel_change_time = osal_get_tick();
		dib8000_autoscan_stop_flag = 0;
		ALI_PRINTF("DIB8000 EXIT CG by USER !!!\n");
		osal_semaphore_release(l_nim_8000_sema_id);
		return ERR_FAILUE;
	}

	tune_diversity(&frontend, 1, &ch);
///*
    for( count = 0 ; count < 50 ; count++ )
    {
        osal_task_sleep(10);
        f_dib8000_get_lock_status(dev,&lock);
        if( lock )
        {
            break;
        }
    }
//*/    
//    osal_task_sleep(500);
	f_dib8000_get_lock_status(dev,&lock);
	
	//if (frontend_get_status(&frontend) == FE_STATUS_LOCKED)
	if(lock)
	{
		dib8000_CurChannelInfo->Lock_Val = 1;
		ALI_PRINTF("f_dib8000_channel_change SUCCESS !!!\n");		
		ret_code = SUCCESS;
	}
	else
	{
		dib8000_CurChannelInfo->Lock_Val = 0;
		ALI_PRINTF("f_dib8000_channel_change FAIL !!!\n");		
		ret_code = ERR_FAILED;
	}

	NIM_PRINTF(" freq=%d, bandwidth=%d, guard_interval=%d, fft_mode=%d, modulation=%d, fec=%d, usage_type=%d, inverse=%d\n\n",  freq, bandwidth, guard_interval, fft_mode, modulation, fec, usage_type, inverse);

	if (guard_interval == guard_1_32)
		Guard = DIBTUNER_GUARD_1_32;
	else if (guard_interval == guard_1_16)
		Guard = DIBTUNER_GUARD_1_16;
	else if (guard_interval == guard_1_8)
		Guard = DIBTUNER_GUARD_1_8;
	else
		Guard = DIBTUNER_GUARD_1_4;

	if (fft_mode == FFT_8K)
		fft_Mode = DIBTUNER_MODE_8K;
	else if (fft_mode == FFT_4K)
		fft_Mode = DIBTUNER_MODE_4K;
	else
		fft_Mode = DIBTUNER_MODE_2K;

	dib8000_CurChannelInfo->CC_Tracking_Frequency = freq;  
	dib8000_CurChannelInfo->CC_Tracking_ChannelBW = bandwidth;
	dib8000_CurChannelInfo->CC_Tracking_Modulation = modulation;
	dib8000_CurChannelInfo->CC_Tracking_Mode = fft_Mode;
	dib8000_CurChannelInfo->CC_Tracking_Guard = Guard;
	dib8000_CurChannelInfo->CC_Tracking_Spectrum = inverse;
	dib8000_CurChannelInfo->CC_Tracking_flag = 0;

    g_last_channel_change_time = osal_get_tick();

	osal_semaphore_release(l_nim_8000_sema_id);
 //   libc_printf("over %d\n", osal_get_tick());

	return ret_code;
}

static INT32 f_dib8000_channel_search(struct nim_device *dev, UINT32 freq, UINT32 bandwidth, 
									   UINT8 guard_interval, UINT8 fft_mode, UINT8 modulation, UINT8 fec, UINT8 usage_type, UINT8 inverse, UINT16 freq_offset, UINT8 priority)
{
	UINT8   i, j;
	INT32   chsearch;
	UINT32  Center_NPRO, Search_NPRO, tmp_freq;
	UINT16 tmp_data;

	NIM_PRINTF("Enter f_dib8000_channel_search()..., freq = %d, bandwidth = %d\n", freq, bandwidth);

	Center_NPRO = (((freq + 36250)*6)/100); 

	for (i=0; i<1; i++)
	{
		chsearch = ERR_FAILED;
		if (dib8000_autoscan_stop_flag)
		{
			dib8000_autoscan_stop_flag = 0;
			return ERR_FAILUE;
		}

		if (i % 2)
			j = 1;
		else
			j = (-1);

		Search_NPRO = (((i+1)/2)*30*j)+Center_NPRO;
		tmp_freq = (Search_NPRO*100)/6;
		
		if (tmp_freq < 36250)
		{
			NIM_PRINTF("f_dib8000_channel_search(): channel search break!!=%d ==> tmp_freq(%d)\n", i, tmp_freq);
			break;      
		}
		else
			freq = tmp_freq - 36250;
	
		chsearch = f_dib8000_channel_change(dev, freq, bandwidth, guard_interval, fft_mode, modulation, fec, usage_type, inverse, priority);
		if (chsearch == SUCCESS)
		{
			break;
		}
	}
	return chsearch;
}

static INT32 f_dib8000_get_freq(struct nim_device *dev, UINT32 *freq)
{
	*freq = dib8000_CurChannelInfo->Frequency;

	NIM_PRINTF("f_dib8000_get_freq(): freq = %d KHz\n", *freq);
	return SUCCESS;
}

static INT32 f_dib8000_get_AGC(struct nim_device *dev, UINT16 *agc)
{
	static UINT16  Data1=0;
	struct dibChannel ch;

	if (dib8000_CurChannelInfo->Lock_Val == 0)
	{
		*agc = 0; 
		return !SUCCESS;
	}
	else
	{
		DiBcom_GetStrength(&Data1);
		dib8000_CurChannelInfo->AGC_Val= Data1;
		*agc = (dib8000_CurChannelInfo->AGC_Val);
		if(*agc>100 )
		{	
			*agc =100;
			dib8000_CurChannelInfo->AGC_Val=100;
		}
		
		//libc_printf("AG=%d\n",*agc);
	}

	return SUCCESS;
}

static INT32 f_dib8000_get_code_rate(struct nim_device *dev, UINT8* code_rate)
{
	NIM_PRINTF("Enter f_dib8000_get_code_rate()...\n");

	struct dibDemodMonitor dibMonitor;
	struct dibChannel cur_ch;

	demod_get_monitoring(&frontend,&dibMonitor);

	cur_ch = dibMonitor.cur_digital_channel;

	//dib8000_CurChannelInfo->HPRates = cur_ch.u.dvbt.code_rate_hp;
	dib8000_CurChannelInfo->HPRates = cur_ch.u.isdbt.layer[0].code_rate;
	NIM_PRINTF("f_dib8000_get_code_rate(): code_rate = %d\n", dib8000_CurChannelInfo->HPRates);

	switch (dib8000_CurChannelInfo->HPRates)
	{
	case DIBTUNER_FEC_1_2:
		*code_rate = FEC_1_2;
		break;
	case DIBTUNER_FEC_2_3:
		*code_rate = FEC_2_3;
		break;
	case DIBTUNER_FEC_3_4:
		*code_rate = FEC_3_4;
		break;
	case DIBTUNER_FEC_5_6:
		*code_rate = FEC_5_6;
		break;
	case DIBTUNER_FEC_7_8:
		*code_rate = FEC_7_8;
		break;
	default:
		ALI_PRINTF("f_dib8000_get_code_rate() ==> Error\n");
		*code_rate = 0;	/* error */
		break;
	}

	NIM_PRINTF("Exit f_dib8000_get_code_rate() normally.\n");
	return SUCCESS;
}

static INT32 f_dib8000_get_fftmode(struct nim_device *dev, UINT8 *fft_mode)
{
	DIBTUNER_Mode_t dib_fft_mode = 0;

	struct dibDemodMonitor dibMonitor;
	struct dibChannel cur_ch;

	demod_get_monitoring(&frontend,&dibMonitor);

	cur_ch = dibMonitor.cur_digital_channel;

	NIM_PRINTF("Enter f_dib8000_get_fftmode()...\n");

	if (cur_ch.u.isdbt.nfft == FFT_2K)
	{
		dib_fft_mode = DIBTUNER_MODE_2K;
	}
	else if (cur_ch.u.isdbt.nfft == FFT_8K)
	{
		dib_fft_mode = DIBTUNER_MODE_8K;
	}
	else if (cur_ch.u.isdbt.nfft == FFT_4K)
	{
		dib_fft_mode = DIBTUNER_MODE_4K;
	}
	dib8000_CurChannelInfo->Mode = dib_fft_mode;
	NIM_PRINTF("f_dib8000_get_fftmode(): fft_mode = %d\n", dib8000_CurChannelInfo->Mode);

	switch (dib8000_CurChannelInfo->Mode)
	{
	case DIBTUNER_MODE_2K:
		*fft_mode = MODE_2K;
		break;
	case DIBTUNER_MODE_8K:
		*fft_mode = MODE_8K;
		break;
	default:
		ALI_PRINTF("f_dib8000_get_fftmode() ==> Error\n");
		*fft_mode = 0xff; /* error */
		break;
	}

	NIM_PRINTF("Exit f_dib8000_get_fftmode() normally.\n");
	return SUCCESS;
}

static INT32 f_dib8000_get_modulation(struct nim_device *dev, UINT8 *modulation)
{
	DIBTUNER_Modulation_t dib_modulation;

	struct dibDemodMonitor dibMonitor;
	struct dibChannel cur_ch;

	demod_get_monitoring(&frontend,&dibMonitor);

	cur_ch = dibMonitor.cur_digital_channel;

	NIM_PRINTF("Enter f_dib8000_get_modulation()...\n");

	//dib8000_CurChannelInfo->Modulation = cur_ch.u.dvbt.constellation;
	dib8000_CurChannelInfo->Modulation = cur_ch.u.isdbt.layer[0].constellation;
	NIM_PRINTF("f_dib8000_get_modulation(): modulation = %d\n", dib8000_CurChannelInfo->Modulation);

	switch (dib8000_CurChannelInfo->Modulation)
	{
	case QAM_QPSK:
		*modulation = TPS_CONST_QPSK;
		break;
	case QAM_16QAM:
		*modulation = TPS_CONST_16QAM;
		break;
	case QAM_64QAM:
		*modulation = TPS_CONST_64QAM;
		break;
	default:
		ALI_PRINTF("f_dib8000_get_modulation() ==> UNKNOWN\n");
		*modulation = 0xff;	/* error */
		break;
	}

	NIM_PRINTF("Exit f_dib8000_get_modulation() normally.\n");
	return SUCCESS; 
}

static INT32 f_dib8000_get_GI(struct nim_device *dev, UINT8 *guard_interval)
{
	DIBTUNER_Guard_t  dib_guard_interval;

	struct dibDemodMonitor dibMonitor;
	struct dibChannel cur_ch;

	demod_get_monitoring(&frontend,&dibMonitor);

	cur_ch = dibMonitor.cur_digital_channel;

	UINT8 tmp_data = 32 / (1 << cur_ch.u.isdbt.guard);

	NIM_PRINTF("Enter f_dib8000_get_GI()...\n");

	if (tmp_data == 4)
	{
		dib8000_CurChannelInfo->Guard = DIBTUNER_GUARD_1_4;
	}
	else if (tmp_data == 6)
	{
		dib8000_CurChannelInfo->Guard = DIBTUNER_GUARD_1_8;
	}
	else if (tmp_data == 16)
	{
		dib8000_CurChannelInfo->Guard = DIBTUNER_GUARD_1_16;
	}
	else if (tmp_data == 32)
	{
		dib8000_CurChannelInfo->Guard = DIBTUNER_GUARD_1_32;
	}

	NIM_PRINTF("f_dib8000_get_GI(): guard_interval = %d\n", dib8000_CurChannelInfo->Guard);

	switch (dib8000_CurChannelInfo->Guard)
	{
	case DIBTUNER_GUARD_1_32:
		*guard_interval = guard_1_32;
		break;
	case DIBTUNER_GUARD_1_16:
		*guard_interval = guard_1_16;
		break;
	case DIBTUNER_GUARD_1_8:
		*guard_interval = guard_1_8;
		break;
	case DIBTUNER_GUARD_1_4:
		*guard_interval = guard_1_4;
		break;
	default:
		ALI_PRINTF("f_dib8000_get_GI() ==> Guard Error\n");
		*guard_interval = 0xff;	/* error */
		break;
	}

	NIM_PRINTF("Exit f_dib8000_get_GI() normally.\n");
	return SUCCESS;
}

static INT32 f_dib8000_get_specinv(struct nim_device *dev, UINT8 *Inv)
{   
	struct dibDemodMonitor dibMonitor;
	struct dibChannel cur_ch;

	demod_get_monitoring(&frontend,&dibMonitor);

	cur_ch = dibMonitor.cur_digital_channel;

	*Inv = cur_ch.u.dvbt.intlv_native;

	return SUCCESS;
}

static INT32 f_dib8000_close(struct nim_device *dev)
{
	frontend_unregister_components(&frontend);
	host_i2c_release(i2c);

	dib8000_CurChannelInfo->Dis_TS_Output = 1;
	NIM_PRINTF("Exit f_dib8000_close() normally.\n");
	return SUCCESS;
}

static INT32 f_dib8000_disable(struct nim_device *dev)
{
	frontend_unregister_components(&frontend);
	host_i2c_release(i2c);

	dib8000_CurChannelInfo->Dis_TS_Output = 1;
	ALI_PRINTF("Enter f_dib8000_disable()...\n");
	NIM_PRINTF("Exit f_dib8000_disable() normally.\n");
	return SUCCESS;
}

static INT32 f_dib8000_get_BER(struct nim_device *dev, UINT32 *vbber)
{     
	NIM_PRINTF("Enter f_dib8000_get_BER()...\n");
	UINT32 ber_raw = data_bus_client_read32(demod_get_data_bus_client(&frontend),500);

	if (dib8000_CurChannelInfo->Lock_Val != 1)
	{
		*vbber = 0;
		return SUCCESS; 
	}
	else
	{
		*vbber = ber_raw;
	}        
	dib8000_CurChannelInfo->BER_Val = *vbber;
	NIM_PRINTF("Exit f_dib8000_get_BER() normally.\n");
	return SUCCESS;
}

static INT32 f_dib8000_get_SNR(struct nim_device *dev, UINT8 *snr)
{

#ifdef NIM_DEBUG
	*snr=100;
	return SUCCESS;
#endif

	UINT32 freq;
	UINT8 bw, module, fft, guard, inverse, priority, usage_type, fec;
	
	//NIM_PRINTF("Enter f_dib8000_get_SNR()...\n");

	static UINT16 tSNR = 0;
	if (dib8000_CurChannelInfo->Lock_Val == 0)
	{
		*snr = 0;
		return SUCCESS;
	}
	else
	{
		//DiBcom_GetQuality(&tSNR);
		//*snr = (UINT8)tSNR;
		if(dib8000_CurChannelInfo->AGC_Val==100)
		*snr =100;
		else
		*snr =dib8000_CurChannelInfo->AGC_Val-2;
	}

	if(*snr >100)
		*snr =100;

	//NIM_PRINTF("f_dib8000_get_SNR()\n");

	//NIM_PRINTF("Exit f_dib8000_get_SNR() normally.\n");
	return SUCCESS;
}


static INT32 f_dib8000_ioctl(struct nim_device *dev, INT32 cmd, UINT32 param)
{
	NIM_PRINTF("Enter f_dib8000_ioctl()...\n");

	switch (cmd)
	{
	case NIM_DRIVER_STOP_ATUOSCAN:
		dib8000_autoscan_stop_flag = param;
		break;
    case NIM_DRIVER_DISABLED:
        return f_dib8000_disable(dev);
        break;
    case NIM_DRIVER_GET_AGC:
        return f_dib8000_get_AGC(dev, (UINT16 *)param);
        break;
    case NIM_DRIVER_GET_BER:
        return f_dib8000_get_BER(dev, (UINT32 *)param);
        break;
    case NIM_DRIVER_GET_GUARD_INTERVAL:
        return f_dib8000_get_GI(dev, (UINT8 *)param);
        break;
    case NIM_DRIVER_GET_FFT_MODE:
        return f_dib8000_get_fftmode(dev, (UINT8 *)param);
        break;
    case NIM_DRIVER_GET_MODULATION:
        return f_dib8000_get_modulation(dev, (UINT8 *)param);
        break;
    case NIM_DRIVER_GET_SPECTRUM_INV:
        return f_dib8000_get_specinv(dev, (UINT8 *)param);
        break;      
	default:
		break;
	}

	NIM_PRINTF("Exit f_dib8000_ioctl() normally.\n");
	return SUCCESS;
}

static INT32 f_dib8000_ioctl_ext(struct nim_device *dev, INT32 cmd, void * param_list)
{
    struct NIM_Channel_Change *change_para;
    struct NIM_Channel_Search *search_para;
	NIM_PRINTF("Enter f_dib8000_ioctl_ext()...\n");
	switch (cmd)
	{
        case NIM_DRIVER_CHANNEL_CHANGE:
            change_para = (struct NIM_Channel_Change *)param_list;
            return f_dib8000_channel_change(dev, change_para->freq, change_para->bandwidth, \
                change_para->guard_interval, change_para->fft_mode, change_para->modulation, \
                change_para->fec, change_para->usage_type, change_para->inverse, change_para->priority);
            break;
        case NIM_DRIVER_CHANNEL_SEARCH:    
            search_para = (struct NIM_Channel_Search *)param_list;
            return f_dib8000_channel_search(dev, search_para->freq, search_para->bandwidth, \
                search_para->guard_interval, search_para->fft_mode, search_para->modulation, \
                search_para->fec, search_para->usage_type, search_para->inverse, \
                search_para->freq_offset, search_para->priority);
            break;
        default:
            break;
	}
	NIM_PRINTF("Exit f_dib8000_ioctl_ext() normally.\n");        
	return SUCCESS;
}


INT32 f_dib8000_attach(struct COFDM_TUNER_CONFIG_API *ptrCOFDM_Tuner)
{
	struct nim_device *dev;
	void  *priv_mem;

	ALI_PRINTF("Enter f_dib8000_attach()...\n");

	dev = (struct nim_device *)dev_alloc(nim_dib8000_name, HLD_DEV_TYPE_NIM, sizeof(struct nim_device));
	if (dev == NULL)
	{
		NIM_PRINTF("f_dib8000_attach(): Error, Alloc nim device error!\n");
		return ERR_NO_MEM;
	}

	/* Alloc structure space of private */
	priv_mem = (void *)MALLOC(sizeof(struct nim_dib8000_private));
	if (priv_mem == NULL)
	{
		dev_free(dev);
		NIM_PRINTF("f_dib8000_attach(): Alloc nim device prive memory error!\n");
		return ERR_NO_MEM;
	}

	MEMCPY(priv_mem, ptrCOFDM_Tuner, sizeof(struct nim_dib8000_private));
	dev->priv = priv_mem;
    gNim_dib8000_private = priv_mem;
	f_IIC_Sema_ID=osal_semaphore_create(1);

	/* Function point init */
	dev->base_addr = SYS_COFDM_DIB8000_CHIP_ADRRESS;
	dev->init = f_dib8000_attach;
	dev->open = f_dib8000_open;
	dev->stop = f_dib8000_close;
	dev->do_ioctl = f_dib8000_ioctl;    
	dev->get_lock = f_dib8000_get_lock_status;
	dev->get_freq = f_dib8000_get_freq;
	dev->get_FEC = f_dib8000_get_code_rate;
	dev->get_SNR = f_dib8000_get_SNR;
	dev->get_BER = f_dib8000_get_BER;
    dev->do_ioctl_ext = f_dib8000_ioctl_ext;

#if(SYS_PROJECT_FE == PROJECT_FE_ISDBT)       
	dev->get_AGC = f_dib8000_get_AGC;
	dev->channel_change = f_dib8000_channel_change;
    dev->disable = f_dib8000_disable;
	dev->get_modulation = f_dib8000_get_modulation;
	dev->get_spectrum_inv = f_dib8000_get_specinv;    
	dev->get_fftmode = f_dib8000_get_fftmode;
	dev->get_guard_interval = f_dib8000_get_GI;
	dev->channel_search = f_dib8000_channel_search;    
#endif
	/* Add this device to queue */
	if (dev_register(dev) != SUCCESS)
	{
		NIM_PRINTF("f_dib8000_attach(): Error, Register nim device error!\n");
		FREE(priv_mem);
		dev_free(dev);
		return ERR_NO_DEV;
	}

	NIM_PRINTF("Exit f_dib8000_attach() normally.\n");
	return SUCCESS;
}

int (*nim8096md_tuner_tune) (struct dibFrontend *fe, struct dibChannel *channel);
static int dib8090_tuner_tune(struct dibFrontend *fe , struct dibChannel *channel)
{
    if (fe->tune_state == CT_TUNER_START) {
        switch(BAND_OF_FREQUENCY(channel->RF_kHz)) {
        default:
            dbgpl(NULL,"Warning : this frequency is not in the supported range, using VHF switch");
        case BAND_VHF: //gpio5 : 0; gpio7 : 0
            demod_set_gpio(fe, 3, 0, 1);
            break;
        case BAND_UHF: //gpio5 : 0; gpio7 : 1
            demod_set_gpio(fe, 3, 0, 0);
            break;
        }
    }

    return nim8096md_tuner_tune(fe, channel);
}


 extern uint16_t dib8000_identify(struct dibDataBusClient *client);
  
 /*modified by alex 2010.11.18 start*/
int f_dib8000_hw_init(struct nim_device *dev)
{
	struct dibChannel ch;

	i2c = host_i2c_interface_attach(NULL);

	if (i2c == NULL)
		return 1;

	frontend_init(&frontend[0]); /* initializing the frontend-structure */
	frontend_set_id(&frontend[0], 0); /* assign an absolute ID to the frontend */
	frontend_set_description(&frontend[0], "ISDB-T #0 Master");

	if (dib8090_sip_register(&frontend[0], i2c, 0x90/*dev->base_addr*/, &nim8096md_config[0]) == NULL)
	{
		libc_printf("DiB7070P: attaching demod and tuners failed.\n");
		return DIB_RETURN_ERROR;
	}
	
	if (dib8000_i2c_enumeration(i2c, 1, DIB8090_DEFAULT_I2C_ADDRESS, 0x90/*dev->base_addr*/) != 0)
	{
		libc_printf("dib8000_i2c_enumeration error\n");
		return DIB_RETURN_ERROR;
	}
	
    nim8096md_tuner_tune = frontend[0].tuner_info->ops.tune_digital;
    frontend[0].tuner_info->ops.tune_digital = dib8090_tuner_tune;
    //dib8090_set_wbd_target(&frontend[0], 250, 425);	
    frontend_reset(&frontend[0]);
    INIT_CHANNEL(&ch, STANDARD_ISDBT);
    libc_printf("f_dib8000_hw_init\n");
/*modified by alex 2010.11.18 end*/
}

void f_dib8000_CC_tracking_task(UINT32 param1)
{           
    UINT32 freq, Pre_TKCount=0, TKCount=0, LKCNT=0;
    UINT32 bandwidth;   
    UINT8 data=0; 
    UINT8 lock=0;
    UINT8 i=0;
    UINT8 agc, snr, BerCNT;
    UINT8  unlock_cnt=0;
	
    while(1)
    {
	     if ((dib8000_CurChannelInfo->Lock_Val == 0)&&(dib8000_CurChannelInfo->CC_Tracking_Frequency!=0))
            {
            		libc_printf("Track_freq=%d\n",dib8000_CurChannelInfo->CC_Tracking_Frequency);
			dib8000_Tracking();
            }
        osal_task_sleep(300);
    }
}


static INT32 f_dib8000_CC_tracking_task_init(struct nim_device *dev)
{
    ER  ret_val;
    OSAL_T_CTSK t_ctsk;    
    t_ctsk.stksz = 0x1000;
    t_ctsk.quantum = 10;
    t_ctsk.itskpri = OSAL_PRI_NORMAL;
    t_ctsk.task = (FP)f_dib8000_CC_tracking_task;
    t_ctsk.para1 = (UINT32)dev;

    f_dib8000_CC_tracking_task_id = osal_task_create(&t_ctsk);
    if(OSAL_INVALID_ID == f_dib8000_CC_tracking_task_id)
    {
        NIM_PRINTF("create_task nim_dib8000_CC_tracking_task_id failed\n");        
        return FALSE;
    }
    return TRUE;
}

void f_dib8000_monitor_task(UINT32 param1)
{
    struct nim_device *dev = param1;
    struct dibChannel ch;
    DWORD now_sys_time = 0;
    UINT16 v;
    UINT8 tmccg_sync_lock=0;

    while(1)
    {
        osal_task_sleep( 200 );
        osal_semaphore_capture(l_nim_8000_sema_id, TMO_FEVR);
        v = data_bus_client_read16(demod_get_data_bus_client(frontend),/*509*/568);
        if( (v >>  3) & 1)	
    		tmccg_sync_lock=1;
    	else
    		tmccg_sync_lock=0;
        now_sys_time = osal_get_tick();

        if( (tmccg_sync_lock == 0) && (g_last_channel_change_time + 50) < now_sys_time )
        {
            INIT_CHANNEL(&ch, STANDARD_ISDBT);
        	ch.RF_kHz           = dib8000_CurChannelInfo->Frequency;
        	ch.bandwidth_kHz    = dib8000_CurChannelInfo->ChannelBW * 1000;
            tune_diversity(&frontend, 1, &ch);
            osal_task_sleep( 400 );
        }
        osal_semaphore_release(l_nim_8000_sema_id);
    }
}

static INT32 f_dib8000_monitor_task_init(struct nim_device *dev)
{
    ER  ret_val;
    OSAL_T_CTSK t_ctsk;    
    t_ctsk.stksz = 0x2000;
    t_ctsk.quantum = 10;
    t_ctsk.itskpri = OSAL_PRI_NORMAL;
    t_ctsk.task = (FP)f_dib8000_monitor_task;
    t_ctsk.para1 = (UINT32)dev;

    f_dib8000_monitor_task_id = osal_task_create(&t_ctsk);
    if(OSAL_INVALID_ID == f_dib8000_monitor_task_id)
    {
        NIM_PRINTF("create_task nim_dib8000_CC_tracking_task_id failed\n");        
        return FALSE;
    }
    return TRUE;
}

static INT32 f_dib8000_open(struct nim_device *dev)
{
	ALI_PRINTF("Enter f_dib8000_open()...\n");

	l_nim_8000_sema_id = osal_semaphore_create(1);
	if (l_nim_8000_sema_id == OSAL_INVALID_ID)
	{
		libc_printf("f_dib8000_open(): Create semaphore fail!\n");
		return ERR_FAILUE;
	}
	dib8000_CurChannelInfo = (struct dib8000_Lock_Info *)MALLOC(sizeof(struct dib8000_Lock_Info));
	if (dib8000_CurChannelInfo == NULL)
	{
		libc_printf("f_dib8000_open(): MALLOC fail!\n");
		return ERR_FAILUE;
	}
	MEMSET(dib8000_CurChannelInfo, 0, sizeof(struct dib8000_Lock_Info));
	NIM_PRINTF("f_dib8000_open(): => f_dib8000_hw_init()...\n");
	if (f_dib8000_hw_init(dev) == DIB_RETURN_ERROR)
	{
		//return ERR_FAILUE;
	}

    f_dib8000_monitor_task_init( dev );

	/*if(FALSE == f_dib8000_CC_tracking_task_init(dev))
	{
        	//libc_printf("f_dib8000_hw_init(): Creak NIM tracking task fail!\n");
    	}*/

	libc_printf("Exit f_dib8000_open() normally.\n");
	return SUCCESS;
}
